package database;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.jboss.netty.buffer.ChannelBuffer;

import system.Config;
import system.L;
import util.ChannelBufferUtil;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.Mongo;

import data.ChallengeRecord;
import data.DBPlayer;
import data.RankPlayer;
import data.SGLocalPlayer;

public class DBMongo {	
	public Mongo _mongo; 
	
	public DBCollection players;
	public DBCollection challenge;
	public DBCollection records;
	private DBCollection _logChallengeCount;
	private DBCollection _logRefreshCount;
	private DBCollection _logLastActive;
	private DBCollection _logRefreshPet;
	private DBCollection _logGuideFinishTime;
	private DBCollection _receipt;
	private DBCollection _logCheat;
	private DBCollection _festState;
//	private DBCollection _logAction;
//	private DBCollection _logLogout;
	
//	public int _today = -1;
//	public SimpleDateFormat _dataFormat = new SimpleDateFormat("yyyy-MM-dd");
//	public String _todayString;
	private Date _todayDate;
	private int _today;
	
	private int[] challengePlayerCount = new int[Config.challengeMax+1];
	private int[] refreshPlayerCount = new int[Config.refreshMax+1];
	
	private BasicDBObject _battlePlayerField;
	private BasicDBObject _countLogQuery = new BasicDBObject();
	
//	private BasicDBObject _setOperation = new BasicDBObject();
//	private BasicDBObject _incOperation = new BasicDBObject();
	
	public DBMongo(Mongo m) {
		_mongo = m;		
		DB db = m.getDB("game");
		DB log = m.getDB("log");
		players = db.getCollection("player");
		players.ensureIndex("guid");
		players.ensureIndex("name");
		challenge = db.getCollection("challenge");
		challenge.ensureIndex("guid");
		records = log.getCollection("record");
		records.ensureIndex("guid");
		records.ensureIndex("name");
		
		_logChallengeCount = log.getCollection("LogChallengeCount");
		_logChallengeCount.ensureIndex("day");
		_logRefreshCount = log.getCollection("LogRefreshCount");		
		_logRefreshCount.ensureIndex("day");
		
		_logLastActive = log.getCollection("LogLastActive");
//		_logLastActive.ensureIndex("guid");
		
		_logRefreshPet = log.getCollection("LogRefreshPet");
//		_logRefreshPet.ensureIndex("guid");
		
//		_logAction = log.getCollection("LogAction");
//		_logLogout = db.getCollection("LogLogout");
		
		_battlePlayerField = new BasicDBObject();
		_battlePlayerField.put("whetherSkillUnlock", 1);
		_battlePlayerField.put("currentPets", 1);		
		
//		_setOperation.put("$set", new BasicDBObject());
//		_incOperation.put("$inc", new BasicDBObject());
		
		_receipt = log.getCollection("receipt");
		_receipt.ensureIndex("guid");
		_receipt.ensureIndex("name");
		if (Config.APP_91) {
			_receipt.ensureIndex("cos");
		}
		
		_logCheat = log.getCollection("cheat");
		_logCheat.ensureIndex("guid");
		_logCheat.ensureIndex("name");
		
		_festState = db.getCollection("fest");
		_festState.ensureIndex("id");
	}	
	
	public boolean updateDate() {
		Date nowDate = Calendar.getInstance().getTime();
		int now = (int)(nowDate.getTime() /1000/60/60/24);
		if (now == _today) return false;
		
//		if (_todayDate != null) {
//		}
		
		_today = now;
		_todayDate = nowDate;
		for (int i = 0; i < challengePlayerCount.length; i++) {
			challengePlayerCount[i] = 0;
			refreshPlayerCount[i] = 0;
		}
		return true;	
	}
	
	synchronized public void flushChallengeCount() {
		BasicDBObject item = new BasicDBObject();
		_countLogQuery.clear();
		_countLogQuery.put("day", _today);
		
		item.put("day", _today);
		item.put("date", _todayDate);
		item.put("counts", challengePlayerCount);
		_logChallengeCount.update(_countLogQuery, item, true, false);
	}
	
	synchronized public void flushRefreshCount() {
		BasicDBObject item = new BasicDBObject();
		_countLogQuery.clear();
		_countLogQuery.put("day", _today);
		item = new BasicDBObject();
		item.put("day", _today);
		item.put("date", _todayDate);
		item.put("counts", refreshPlayerCount);
		_logRefreshCount.update(_countLogQuery, item, true, false);
	}
	
//	synchronized public void flushChallengeAndRefreshCount() {
//		BasicDBObject item = new BasicDBObject();
//		_countLogQuery.clear();
//		_countLogQuery.put("day", _today);
//		
//		item.put("day", _today);
//		item.put("date", _todayDate);
//		item.put("counts", challengePlayerCount);
//		_logChallengeCount.update(_countLogQuery, item, true, false);
//		
//		item = new BasicDBObject();
//		item.put("day", _today);
//		item.put("date", _todayDate);
//		item.put("counts", refreshPlayerCount);
//		_logRefreshCount.update(_countLogQuery, item, true, false);
//	}
	
	public void decreaseChallengeCount(int count) {
		challengePlayerCount[count] = Math.max(0, challengePlayerCount[count]-1);
	}
	
	public void increaseChallengeCount(int count) {		
		updateDate();
		challengePlayerCount[count]++;
		flushChallengeCount();
	}
	
	public void logChallengeCount(int oldCount, int newCount) {
		decreaseChallengeCount(oldCount);
		increaseChallengeCount(newCount);
	}
	
	public void decreaseRefreshCount(int count) {
		refreshPlayerCount[count] = Math.max(0, refreshPlayerCount[count]-1);
	}
	
	public void increaseRefreshCount(int count) {
		updateDate();
		refreshPlayerCount[count]++;
		flushRefreshCount();
	}
	
	public void logRefreshCount(int oldCount, int newCount) {
		decreaseRefreshCount(oldCount);
		increaseRefreshCount(newCount);
	}
	
	public void logRefreshPet(String guid, String name, int quality, int nation, int profile) {
		BasicDBObject query = new BasicDBObject();
		query.put("quality", quality);
		BasicDBObject update = new BasicDBObject();
		update.put("N"+nation, 1);
		BasicDBObject _incOperation = new BasicDBObject();
		_incOperation.put("$inc", update);		
		_logRefreshPet.update(query, _incOperation, true ,false);
//		BasicDBObject _logRefreshPetInsert = new BasicDBObject();
//		_logRefreshPetInsert.put("guid", guid);
//		_logRefreshPetInsert.put("name", name);
//		_logRefreshPetInsert.put("quality", quality);
//		_logRefreshPetInsert.put("nation", nation);
//		_logRefreshPetInsert.put("profile", profile);
//		_logRefreshPetInsert.put("date", Calendar.getInstance().getTime());
//		_logRefreshPet.insert(_logRefreshPetInsert);
	}
	
	public void logGuideFinish(String guid, String name, int cost) {
		BasicDBObject query = new BasicDBObject("cost", cost);
		BasicDBObject update = new BasicDBObject("count", 1);
		BasicDBObject _incOperation = new BasicDBObject();
		_incOperation.put("$inc", update);
		_logGuideFinishTime.update(query, _incOperation, true, false);
	}

	public BasicDBObject findPlayerFromDB(String guid, BasicDBObject query) {
		query.clear();
		query.put("guid", guid);
		return (BasicDBObject) players.findOne(query);
	}
	
	public BasicDBObject findPlayerFromDBByName(String name, BasicDBObject query) {
		query.clear();
		query.put("name", name);
		return (BasicDBObject) players.findOne(query);
	}
	
	public BasicDBObject findRecord(String guid, BasicDBObject query) {
		query.clear();
		query.put("guid", guid);
		return (BasicDBObject) records.findOne(query);
	}
	
//	public BasicDBObject findPlayerByName(String name, BasicDBObject query) {
//		query.clear();
//		query.put("name", name);
//		return (BasicDBObject) players.findOne(query);
//	}
	
	public void savePlayer(BasicDBObject dbp) {
		players.save(dbp);
	}
	
//	public void upsertPlayerDB(String guid, BasicDBObject query,
//			BasicDBObject data) {
//		query.clear();
//		query.put("guid", guid);
//		BasicDBObject player = new BasicDBObject();
//		player.put("record", data);
//		players.update(query, player, true, false);
//	}
	
	public boolean checkRecordExsit(String guid, BasicDBObject query) {
		query.clear();
		query.put("guid", guid);
		return records.count(query) > 0;
	}
	
	public DBPlayer creartPlayer(SGLocalPlayer player) {
		BasicDBObject update = new BasicDBObject();
		update.put("guid", player.getGUID());
		update.put("name", player.getName());
		update.put("level", player.getLevel());
		update.put("sex", player.getSex());
		update.put("pvpScore", 0);
		update.put("pvpWinCount", 0);
		update.put("pvpCount", 0);
		update.put("pvpLevel", 0);
		update.put("lastEnterPVPTime", (long)0);
		update.put("lastActiveTime", System.currentTimeMillis());
		update.put("lastChallangeDay", 0); 
		update.put("todayChallangeCount", 0);
		DBPlayer result = new DBPlayer();
		result.db = update;
		return result;		
	}
	
	public void insertPlayer(BasicDBObject query, DBPlayer player) {
		query.clear();
		query.put("guid", player.getGUID());
		BasicDBObject update = player.db;
		players.update(query, update, true, false);
	}
	
	public void insertPlayer(BasicDBObject query, RankPlayer player) {
		query.clear();
		query.put("guid", player.guid);
		BasicDBObject update = new BasicDBObject();
		update.put("guid", player.guid);
		update.put("name", player.name);
		update.put("level", player.level);
		update.put("sex", player.sex);
		update.put("pvpScore", player.pvpScore);
		update.put("pvpWinCount", player.pvpWinCount);
		update.put("pvpCount", player.pvpCount);
		update.put("pvpLevel", player.pvpLevel);
		update.put("lastEnterPVPTime", (long)0);
		update.put("lastActiveTime", System.currentTimeMillis());
		update.put("unreadCount", 0);
		update.put("registerDate", Calendar.getInstance().getTime());
		players.update(query, update, true, false);
	}
	
	public void convertToPlayer(BasicDBObject playerDB, RankPlayer player) {
		player.level = playerDB.getInt("level");
		player.name = playerDB.getString("name");
		player.sex = playerDB.getInt("sex");
		player.guid = playerDB.getString("guid");
		player.pvpScore = playerDB.getInt("pvpScore");
		player.pvpWinCount = playerDB.getInt("pvpWinCount");
		player.pvpCount = playerDB.getInt("pvpCount");
		player.updatePVPWinPercent();
	}
	
	public void updatePlayerPVP(BasicDBObject query, DBPlayer player) {
		query.clear();
		query.put("guid", player.getGUID());
		BasicDBObject update = new BasicDBObject();		
		update.put("pvpScore", player.getPvpScore());
		update.put("pvpWinCount", player.getPvpWinCount());
		update.put("pvpCount", player.getPvpCount());
		update.put("pvpLevel", player.getPVPLevel());
		update.put("lastActiveTime", System.currentTimeMillis());
		update.put("unreadCount", player.getUnreadCount());
		BasicDBObject _setOperation = new BasicDBObject();
		_setOperation.put("$set", update);
		players.update(query, _setOperation, true, false);
	}
	
	public void updatePlayerLevel(BasicDBObject query, String guid, int level) {
		query.clear();
		query.put("guid", guid);
		BasicDBObject update = new BasicDBObject();
		update.put("level", level);
		update.put("lastActiveTime", System.currentTimeMillis());
		BasicDBObject _setOperation = new BasicDBObject();
		_setOperation.put("$set", update);
		players.update(query, _setOperation);
	}
	
	public BasicDBObject findBattlePlayerFromDB(String guid, BasicDBObject query) {
		query.clear();
		query.put("guid",guid);
		return (BasicDBObject) records.findOne(query, _battlePlayerField);
	}
	
	public void saveClientRecord(BasicDBObject query, BasicDBObject data) {
		query.clear();
		query.put("guid", data.get("guid"));
		records.update(query, data, true, false);
	}
	
//	public void updateTrainRankDB(BasicDBObject query, BasicDBObject update,
//			String guid, RankPlayer node) {
//		update.put("trainLevel", node.trainLevel);
//		update.put("trainRank", node.trainRank);
//		query.put("guid", guid);
//		players.update(query, new BasicDBObject("$set", update));
//	}
	

	public void logActive(String name, String guid, int level, int stage, int subStage, int currentMainTask) {
		BasicDBObject _logActiveQuery = new BasicDBObject();
		BasicDBObject _logActiveUpdate = new BasicDBObject();
		_logActiveQuery.put("guid", guid);
		_logActiveUpdate.put("guid", guid);
		_logActiveUpdate.put("name", name);
		_logActiveUpdate.put("level", level);
		_logActiveUpdate.put("stage", stage);
		_logActiveUpdate.put("subStage", subStage);
		_logActiveUpdate.put("currentMainTask", currentMainTask);
		_logActiveUpdate.put("date", Calendar.getInstance().getTime());
		_logActiveUpdate.put("time", System.currentTimeMillis());
		BasicDBObject _setOperation = new BasicDBObject();
		_setOperation.put("$set", _logActiveUpdate);
		_logLastActive.update(_logActiveQuery, _logActiveUpdate, true, false);
	}
	
	public void logLogin(String name, String guid, String date, BasicDBObject query, long time) {
//		query.clear();
//		query.put("guid", guid);
//		query.put("name", name);
//		query.put("date", date);
//		query.put("time", time);
//		query.put("action", "login");
//		_logAction.insert(query);
	}
	
	public void logLogout(String name, String guid, String date, BasicDBObject query, long time) {
//		query.clear();
//		query.put("guid", guid);
//		query.put("name", name);
//		query.put("date", date);
//		query.put("time", time);
//		query.put("action", "logout");
//		_logAction.insert(query);
	}
	
	public boolean checkNameExsit(String name, BasicDBObject query) {
		query.clear();
		query.put("name", name);
		return records.count(query) > 0;
	}
	
	public void serializePlayer(BasicDBObject db, ChannelBuffer buf) {
		ChannelBufferUtil.writeString(buf, db.getString("guid"));
		buf.writeByte(db.getInt("sex"));
		ChannelBufferUtil.writeString(buf, db.getString("name"));
		buf.writeInt(db.getInt("level"));
		buf.writeInt(db.getInt("pvpScore"));
		buf.writeInt(db.getInt("pvpRank"));
		buf.writeInt(db.getInt("pvpWinPercent"));
	}
	
	public void addChallengeRecord(String guid, String enemyGuid, boolean win, int isChallenger) {
		ChallengeRecord record = getChallengeResult(guid);
		record.add(enemyGuid, win, isChallenger);
		saveChallengeRecord(guid, record);
	}
	
	public ChallengeRecord getChallengeResult(String guid) {
		BasicDBList list = null;
		BasicDBObject row = (BasicDBObject)challenge.findOne(new BasicDBObject("guid", guid));
		if (row != null) {
			list = (BasicDBList)row.get("list");
		}
		return new ChallengeRecord(list);
	}
	
	public void saveChallengeRecord(String guid, ChallengeRecord record) {
		BasicDBList list = new BasicDBList();
		record.writeDB(list);
		BasicDBObject query = new BasicDBObject("guid", guid);
		BasicDBObject update = new BasicDBObject("list", list);		
		challenge.update(query, new BasicDBObject("$set", update), true, false);
	}
	
	public void saveChallengeCount(DBPlayer player) {
		BasicDBObject query = new BasicDBObject("guid", player.getGUID());
		BasicDBObject update = new BasicDBObject();
		update.put("lastChallangeDay", player.getLastChallangeDay()); 
		update.put("todayChallangeCount", player.getTodayChallengeCount());
		players.update(query, new BasicDBObject("$set", update), true, false);
	}
	
	public void addReceipt(String guid, String json, String name) {
		BasicDBObject row = new BasicDBObject();
		row.put("guid", guid);
		row.put("json", json);
		row.put("name", name);
		_receipt.insert(row);
	}
	
	public boolean hasReceipt(String guid, String json) {
		BasicDBObject query = new BasicDBObject("guid", guid);
		DBCursor cursor = _receipt.find(query);
		BasicDBObject row;
		while (cursor.hasNext()) {
			row = (BasicDBObject)cursor.next();
			if (row.getString("json").equals(json)) {
				return true;
			}
		}
		return false;
	}
	
	public void addReceipt91(String guid, String cos, String name, String detail) {
		BasicDBObject row = new BasicDBObject();
		row.put("guid", guid);
		row.put("cos", cos);
		row.put("name", name);
		row.put("detail", detail);
		_receipt.insert(row);
	}
	
	public boolean hasReceipt91(String cos) {
		BasicDBObject query = new BasicDBObject("cos", cos);
		return _receipt.count(query) > 0;
	}
	
	public boolean hasPurchase(String guid) {
		BasicDBObject query = new BasicDBObject("guid", guid);
		return _receipt.count(query) > 0;
	}
	
	public void resetUnreadCount(String guid) {
		BasicDBObject query = new BasicDBObject();
		query.put("guid", guid);
		BasicDBObject update = new BasicDBObject();
		update.put("unreadCount", 0);
		BasicDBObject setOperation = new BasicDBObject();
		setOperation.put("$set", update);
		players.update(query, setOperation);
	}
	
	public void removePlayer(String guid) {
		BasicDBObject query = new BasicDBObject();
		query.put("guid", guid);
		players.remove(query);
	}
	
	public void logCheat(String guid, String name, int type) {
		BasicDBObject query = new BasicDBObject("guid", guid);
		BasicDBObject update = new BasicDBObject();
		update.put("date", Calendar.getInstance().getTime());
		update.put("guid", guid);
		update.put("name", name);
		update.put("type"+type, true);
		_logCheat.update(query, new BasicDBObject("$set", update), true, false);
	}
	
	public void setFestState(String id, int state) {
		BasicDBObject query = new BasicDBObject("id", id);
		BasicDBObject update = new BasicDBObject();
		update.put("state", state);
		_festState.update(query, new BasicDBObject("$set", update), true, false);
	}
	
	public Map<String, Integer> loadFestState() {
		Map<String, Integer> result = new HashMap<String, Integer>();
		DBCursor it = _festState.find();
		BasicDBObject row;
		String id;
		int state;
		while (it.hasNext()) {
			row = (BasicDBObject)it.next();
			id = row.getString("id");
			state = row.getInt("state");
			result.put(id, state);
			L.info("load fest state, id:"+id + " state:" + state);
		}
		return result;
	}
	
	public DBCursor getCheats() {
		return _logCheat.find();
	}
}
